import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Scanner;

public class SudokuChecker {
    public static void main(String[] args) throws FileNotFoundException {
        int[][] board = readBoard("boards/board2.txt");
        System.out.println(Arrays.deepToString(board));
    }

    /**
     * Uses scanner to read a completed sudoku board from a file
     * and stores it as a 9-by-9 2-dimensional array
     * @param filepath
     * @return the 2D array of integers representing the sudoku board
     * @throws FileNotFoundException
     */
    public static int[][] readBoard(String filepath) throws FileNotFoundException {
        FileInputStream fileInputStream = new FileInputStream(filepath);
        Scanner scanner = new Scanner(fileInputStream);
        int[][] board = new int[9][9];
        for (int i = 0; i < 9; i++) {
            for (int j = 0; j < 9; j++) {
                board[i][j] = scanner.nextInt();
            }
        }
        // Task 1: read the integers with scanner and save them into the array board
        scanner.close();
        return board;
    }

    /**
     * Gets the 9 integers in a 3-by-3 box on a sudoku board
     * @param board a 9-by-9 2D array
     * @param i
     * @param j
     * @return an array containing the 9 integers from the box
     */
    static int[] getBox(int[][] board, int i, int j) {
        int[] box = new int[9];
        // Task 2: get the 9 integers from the box
        int idx = 0;
        for (int row = i * 3; row < i * 3 +3; row++) {
            for (int column = j * 3; column < j * 3 + 3; column++) {
                box[idx] = board[row][column];
                idx++;
            }
        }
        return box;
    }

    /**
     * Gets the 9 integers in the ith (horizontal) row on the sudoku board
     * @param board a 9-by-9 2D array
     * @param i index of the row
     * @return an array containing the 9 integers from the row
     */
    static int[] getRow(int[][] board, int i) {
        int[] row = new int[9];
        // Task 3: get the 9 integers from the ith row
        for (int j = 0; j < 9; j++) {
            row[j] = board[i][j];
        }
        return row;
    }

    /**
     * Gets the 9 integers in the jth (vertical) column on the sudoku board
     * @param board a 9-by-9 2D array
     * @param j index of the column
     * @return an array containing the 9 integers from the column
     */
    static int[] getColumn(int[][] board, int j) {
        int[] column = new int[9];
        for (int i = 0; i < 9; i++) {
            column[i] = board[i][j];
        }
        // Task 4: get the 9 integers from the jth column
        return column;
    }

    /**
     * Looks for a certain number in an array
     * @param nums an array of integers
     * @param n the integer to be looked for
     * @return true if the number is found, else false
     */
    static boolean findNumber(int[] nums, int n) {

        // Task 5: check if number n is present in array nums and return a boolean
        for (int num : nums) {
            if (num == n) {
                return true;
            }
        }
        return false; // This line should be removed
    }

    /**
     * Checks if each integer from 1 to 9 (inclusive) appears exactly once in an array
     * @param nums an array of integers
     * @return true of the array contains exactly one of each number from 1 to 9, else false
     */
    static boolean checkNumbers(int[] nums) {
        // Task 6: check if each number from 1 to 9 is found in array nums
        for (int i = 1; i < 10; i++){
            if (!findNumber(nums, i)) {
                return false;
            }
        }

        return true;
        }


    /**
     * Checks if each of the 9 rows on a completed sudoku board contains the correct numbers
     * @param board a 9-by-9 2D array
     * @return true if each of the 9 rows contains the correct numbers, else false
     */
    static boolean checkRows(int[][] board) {
        for (int i = 0; i < 9; i++) {
            if(!checkNumbers(getRow(board,i))){
                return false;
            }
        }
        return true;
        // Task 7: use a loop to check the 9 rows
    }

    /**
     * Checks if each of the 9 columns on a completed sudoku board contains the correct numbers
     * @param board a 9-by-9 2D array
     * @return true if each of the 9 columns contains the correct numbers, else false
     */
    static boolean checkColumns(int[][] board) {
        // Task 8: use a loop to check the 9 columns
        for (int i = 0; i < 9; i++) {
            if(!checkNumbers(getColumn(board,i))){
                return false;
            }
        }
        return true;
    }

    /**
     * Checks if each of the 9 3-by-3 box on a completed sudoku board contains the correct numbers
     * @param board a 9-by-9 2D array
     * @return true if each of the 9 boxes contains the correct numbers, else false
     */
    static boolean checkBoxes(int[][] board) {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j ++) {
                int[] box = getBox(board, i, j);
                if (!checkNumbers(box)) {
                    System.out.println("Box (" + (i + 1) + ", " + (j + 1) + ") contains errors!");
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * Checks if a completed sudoku board represents a valid solution to the sudoku game
     * @param board a 9-by-9 2D array
     * @return true if the solution is valid, else false
     */
    public static boolean checkBoard(int[][] board) {
        boolean validRows = checkRows(board);
        boolean validColumns = checkColumns(board);
        boolean validBoxes = checkBoxes(board);
        return validRows && validColumns && validBoxes;
    }
}

